package com.ruoyi.video.server.onvif.lib;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.ruoyi.video.domain.OnvifCamera;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringEscapeUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;


@Component
@Slf4j
public class OnvifApi {
	@Autowired
	private RestTemplate restTemplate;

	public String stream(OnvifCamera videoCamera) {
		//判断是否已获取token
		String token = this.getToken(videoCamera);
		//构造http请求头
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("text/xml;charset=UTF-8");
		headers.setContentType(type);
		HttpEntity<String> formEntity = new HttpEntity<String>(PackageXml.streamUri(videoCamera.getUsername(),videoCamera.getPassword(),token), headers);
		//返回结果
		String resultStr = restTemplate.postForObject("http://"+videoCamera.getIp()+":"+videoCamera.getPort()+"/onvif/device_service", formEntity, String.class);
		//转换返回结果中的特殊字符，返回的结果中会将xml转义，此处需要反转移
		String xmlStr = StringEscapeUtils.unescapeXml(resultStr);
		log.debug("{} onvif get stream response:\r\n{}", videoCamera.getIp(), xmlStr);
		//JSONObject obj = XML.toJSONObject(tmpStr);
		String reg = "<tt:Uri>(.*?)\\</tt:Uri>";
        Pattern pattern = Pattern.compile(reg);
        // 内容 与 匹配规则 的测试
        Matcher matcher = pattern.matcher(xmlStr);
        if(matcher.find()){
            // 包含前后的两个字符 
            //System.out.println(matcher.group());
            // 不包含前后的两个字符
        	String rtspUrl = matcher.group(1).replace("rtsp://", "rtsp://"+videoCamera.getUsername()+":"+videoCamera.getPassword()+"@");
            videoCamera.setRtsp(rtspUrl);
			return rtspUrl;
        }else{
            //System.out.println(" 没有匹配到内容....");
        	return null;
        }
	}
	public Boolean ptz(OnvifCamera videoCamera, Double leftRight, Double upDown, Double inOut) {
		if(leftRight==null) {
			leftRight = 0.0;
		}
		if(upDown==null) {
			upDown = 0.0;
		}
		if(leftRight>1 && leftRight<-1) {
			return false;
		}
		if(upDown>1 && upDown<-1) {
			return false;
		}
		if(inOut>1 && inOut<-1) {
			return false;
		}
		//判断是否已获取token
		String token = this.getToken(videoCamera);
		//构造http请求头
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("text/xml;charset=UTF-8");
		headers.setContentType(type);
		String xml = PackageXml.ptz(videoCamera.getUsername(),videoCamera.getPassword(),token,leftRight,upDown,inOut);
		HttpEntity<String> formEntity = new HttpEntity<String>(xml,headers);
		//返回结果
		String resultStr = restTemplate.postForObject("http://"+videoCamera.getIp()+":"+videoCamera.getPort()+"/onvif/device_service", formEntity, String.class);
		//转换返回结果中的特殊字符，返回的结果中会将xml转义，此处需要反转移
		String xmlStr = StringEscapeUtils.unescapeXml(resultStr);
		log.debug("{} onvif ptz response:\r\n{}", videoCamera.getIp(), xmlStr);
		//JSONObject obj = XML.toJSONObject(tmpStr);
        return true;
	}

	public void getInfo(OnvifCamera videoCamera) {
		//判断是否已获取token
		String token = this.getToken(videoCamera);
		//构造http请求头
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("text/xml;charset=UTF-8");
		headers.setContentType(type);
		HttpEntity<String> formEntity = new HttpEntity<String>(PackageXml.info(videoCamera.getUsername(),videoCamera.getPassword(), token), headers);
		//返回结果
		String resultStr = restTemplate.postForObject("http://"+videoCamera.getIp()+":"+videoCamera.getPort()+"/onvif/device_service", formEntity, String.class);
		log.debug("{} onvif get info response:\r\n{}", videoCamera.getIp(), resultStr);
		//转换返回结果中的特殊字符，返回的结果中会将xml转义，此处需要反转移
		String xmlStr = StringEscapeUtils.unescapeXml(resultStr);
		//JSONObject obj = XML.toJSONObject(tmpStr);
		String reg = "<tds:SerialNumber>(.*?)\\</tds:SerialNumber>";
		Pattern pattern = Pattern.compile(reg);
		// 内容 与 匹配规则 的测试
		Matcher matcher = pattern.matcher(xmlStr);
		if(matcher.find()){
			videoCamera.setDeviceId(matcher.group(1));
		}
		reg = "<tds:Manufacturer>(.*?)\\</tds:Manufacturer>";
		pattern = Pattern.compile(reg);
		// 内容 与 匹配规则 的测试
		matcher = pattern.matcher(xmlStr);
		if(matcher.find()){
			videoCamera.setManufacturer(matcher.group(1));
		}

		reg = "<tds:Model>(.*?)\\</tds:Model>";
		pattern = Pattern.compile(reg);
		// 内容 与 匹配规则 的测试
		matcher = pattern.matcher(xmlStr);
		if(matcher.find()){
			videoCamera.setModel(matcher.group(1));
		}
	}

	/**
	 * 登录获取令牌
	 * @param videoCamera
	 * @return
	 */
	public String getToken(OnvifCamera videoCamera) {
		try {
			// 构造http请求头
			HttpHeaders headers = new HttpHeaders();
			MediaType type = MediaType.parseMediaType("text/xml;charset=UTF-8");
			headers.setContentType(type);
			String tokenXml = PackageXml.token(videoCamera.getUsername(), videoCamera.getPassword());
			HttpEntity<String> formEntity = new HttpEntity<String>(tokenXml, headers);
			// 返回结果
			String resultStr = restTemplate.postForObject("http://" + videoCamera.getIp() + ":" + videoCamera.getPort() + "/onvif/device_service", formEntity,String.class);
			// 转换返回结果中的特殊字符，返回的结果中会将xml转义，此处需要反转移
			String xmlStr = StringEscapeUtils.unescapeXml(resultStr);
			log.debug("{} onvif get token response:\r\n{}", videoCamera.getIp(), xmlStr);
			SAXReader reader = new SAXReader();
			Document document = reader.read(new ByteArrayInputStream(xmlStr.getBytes("UTF-8")));
			Element root = document.getRootElement();
			if(root == null || root.element("Body") == null){
				return null;
			}
			String token = root.element("Body").element("GetProfilesResponse").elements("Profiles").get(0).attribute("token").getText();
			return token;
		} catch (RestClientException | DocumentException | UnsupportedEncodingException e) {
			return null;
		} 
	}
}
